package com.guguguweb.rpc.register.imp;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.guguguweb.rpc.enumeration.RpcError;
import com.guguguweb.rpc.exception.RpcException;
import com.guguguweb.rpc.loadbalancer.LoadBalancer;
import com.guguguweb.rpc.register.ServiceDiscovery;
import com.guguguweb.rpc.util.NacosUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class NacosServiceDiscovery implements ServiceDiscovery {

    private LoadBalancer loadBalancer;

    private Map<String,List<Instance>> instanceCache = new ConcurrentHashMap<>();

    private Map<String,Long> timeCache = new ConcurrentHashMap<>();

    private NacosUtil nacosUtil;


    public NacosServiceDiscovery(LoadBalancer loadBalancer, NacosUtil nacosUtil){
        this.loadBalancer = loadBalancer;
        this.nacosUtil = nacosUtil;
    }


    private final static long cacheInstanceTime = 30000L;

    /**
     *
     * @param serviceName
     * @return InetSocketAddress
     * 返回可用服务的IP地址，不存在则抛出异常
     */
    @Override
    public InetSocketAddress lookupService(String serviceName) {
        List<Instance> instances = instanceCache.get(serviceName);
        if(instances == null || instances.isEmpty()){
            try {
                instances = reFlushCache(serviceName);
            } catch (NacosException e) {
                throw new RuntimeException(e);
            }
        }else if(System.currentTimeMillis() - timeCache.get(serviceName) >= cacheInstanceTime){
            try {
                instances = reFlushCache(serviceName);
            } catch (NacosException e) {
                timeCache.put(serviceName,System.currentTimeMillis());
                throw new RuntimeException(e);
            }
        }

        if(instances == null ||instances.size() == 0){
            log.error("找不到对应服务：" + serviceName);
            throw new RpcException(RpcError.SERVICE_NOT_FOUND );
        }
        Instance select = loadBalancer.select(instances);
        return new InetSocketAddress(select.getIp(),select.getPort());
    }

    public List<Instance> reFlushCache(String serviceName) throws NacosException{
        List<Instance> instances = null;
        try {
            instances = nacosUtil.getAllInstance(serviceName);
            instanceCache.put(serviceName,instances);
            timeCache.put(serviceName,System.currentTimeMillis());
        } catch (NacosException e) {
            log.error("nacos 获取服务列表出错 ！, serviceName : {},{}",serviceName,e);
            throw e;
        }
        return instances;
    }

    @Override
    public void deleteConsumer(String serviceName, InetSocketAddress address) {
        if(StringUtils.isBlank(serviceName) ||address == null){
            return;
        }
        List<Instance> instances = instanceCache.get(serviceName);
        Iterator<Instance> iterator = instances.iterator();
        while (iterator.hasNext()){
            Instance next = iterator.next();
            if(next.getIp().equals(address.getHostName()) || next.getPort() == address.getPort()){
                iterator.remove();
            }
        }
    }
}
